package control;

import dao.AccountDAO;
import dao.ContactListDAO;
import dao.MessageDAO;
import dto.Account;
import dto.Message;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import service.ChatClientService;
import service.ChatServerService;
import view.AdminView;

public class ServerController {

    private AccountDAO accountDAO;
    private ContactListDAO contactListDAO;
    private MessageDAO messageDAO;
    private AdminView adminView;
    private Registry reg;
    private boolean ServerOnline;
    private ChatServerServiceImpl serverImp;

    public ServerController() {
        try {
            reg = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
            serverImp = new ChatServerServiceImpl(this);
             accountDAO = new AccountDAO();
            contactListDAO = new ContactListDAO();
            adminView = new AdminView();
            messageDAO = new MessageDAO();
            adminView.setVisible(true);
            adminView.setServer(this);
        } catch (RemoteException e) {
            System.err.println("Registry can not be created");
        }
    }

    public boolean signUp(Account a) {
        return accountDAO.addAccount(a);
    }

    public void signIn(Account account) throws Exception {
        accountDAO.checkRegisteredAccount(account);
    }
    
    public void updateLoginAdminView() {
        adminView.updateOnline(adminView.getOnline() + 1);
        adminView.updateOffline(adminView.getOffline() - 1);
    }
    
    public void updateSignUpAdminView() {
        adminView.updateOffline(adminView.getOffline() + 1);
    }

    public boolean checkExistingAccout(Account account) {
        return accountDAO.checkExistingAccout(account);

    }

    public void startServer() {
        try {
            serverImp = new ChatServerServiceImpl(this);
            ChatServerService stub = (ChatServerService) UnicastRemoteObject.exportObject(serverImp, 0);
            reg.rebind("ChatService", stub);
            ServerOnline = true;
            adminView.updateOffline(accountDAO.getCount());
        } catch (SQLException ex) {
            Logger.getLogger(ServerController.class.getName()).log(Level.SEVERE, null, ex);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    public void stopServer() {
        try {
            reg.unbind("ChatService");
            ServerOnline = false;
            serverImp.getClients().clear();
        } catch (RemoteException | NotBoundException e) {
            e.printStackTrace();
        }
    }
    /**
     * get the Account of user According to his/her mail.
     */
    public Account getAccountByMail(String mail) {
        return accountDAO.getAccount(mail);
    }
    /**
     * get Contact List for each user.
     */
    public Vector<Account> getContactList(Account account) {
        return contactListDAO.getContactList(account);
    }
    /**
     * Add new Contact.
     */
    public void addContact(Account userWhoAdd, Account userWhoReply) {
        contactListDAO.addContact(userWhoAdd, userWhoReply);
    }

    /**
     * Remove Contact from contact List.
     */
    public Boolean removeContact(String mail, Account account) {
        return contactListDAO.removeContact(mail, account);
    }

    public static void main(String[] args) {
        new ServerController();
    }

    /**
     * storeFriendrequest in DB.
     */
    public void storeFriendrequest(String sendermail, String receiver) {
        contactListDAO.storeFriendrequest(sendermail, receiver);
    }
    /**
     * checks if there 're Pinned Friend Requests in DB.
     */
    public void checkPinnedFriendRequest(ChatClientService clientService) {
        contactListDAO.checkPinnedFriendRequest(clientService);
    }

     /**
     * checks if there 're Pinned Friend Request Reply in DB.
     */
    public void checkPinnedFriendRequestReply(ChatClientService clientService) {
        contactListDAO.checkPinnedFriendRequestReply(clientService);
    }
    /**
     * store Friend request Reply in DB.
     */
    public void storeFriendrequestReply(String userWhoAddmail, String userWhoReplymail, int reply) {
        contactListDAO.storeFriendrequestReply(userWhoAddmail, userWhoReplymail, reply);
    }

    void saveMessage(Message message, Account member) {
        try {
            messageDAO.saveMessage(message, member);
        } catch (SQLException ex) {
            Logger.getLogger(ServerController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * @return the isServerOnline
     */
    public boolean IsServerOnline() {
        return ServerOnline;
    }

    /**
     * @param isServerOnline the isServerOnline to set
     */
    public void setIsServerOnline(boolean isServerOnline) {
        this.ServerOnline = isServerOnline;
    }

    /**
     * @return the serverImp
     */
    public ChatServerServiceImpl getServerImp() {
        return serverImp;
    }

    /**
     * @param serverImp the serverImp to set
     */
    public void setServerImp(ChatServerServiceImpl serverImp) {
        this.serverImp = serverImp;
    }

    public void propagateCloseAction() {
        System.out.println(serverImp.getClients().size());
        Collection c = serverImp.getClients().values();
        Iterator it = c.iterator();
        while (it.hasNext()) {
            try {
                ChatClientService client = (ChatClientService) it.next();
                client.terminateAbnormaly();
            } catch (RemoteException ex) {
                Logger.getLogger(ServerController.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    Vector<Message> getOfflineMessage(Account loggedInAccount) {
        try {
            int id = accountDAO.getAccountId(loggedInAccount.getEmail());
            Vector<Message> messages = messageDAO.getMessages(id);
            messageDAO.deleteMessages(id);
            return messages;


        } catch (SQLException ex) {
            Logger.getLogger(ServerController.class
                    .getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    /**
     * Add new Announcements.
     */
    public void addAnnouncements(String announcement) {
        serverImp.addAnnouncements(announcement);
    }

    void logoutUpdateAdmin(String sessionEmail) {
        Account account = new Account();
        account.setEmail(sessionEmail);
        try {
            serverImp.logout(account);
            adminView.updateOnline(adminView.getOnline() - 1);
            adminView.updateOffline(adminView.getOffline() + 1);
        } catch (RemoteException ex) {
            Logger.getLogger(ServerController.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }
    
    public Vector<Vector> GetDbAccounts()
    {
        return accountDAO.getAllAccounts();
    }
}
